Regular ifodalar yordamida JavaScript-da ilg'or andaza moslashuvini o'rganing. Samarali va barqaror kod uchun regex sintaksisi, amaliy qo'llanmalar va optimallashtirish usullarini o'rganing.
JavaScript-da Regular Ifodalar bilan Andaza Moslashuvi: To'liq Qo'llanma
Regular ifodalar (regex) JavaScript-da andazalarni moslashtirish va matnni boshqarish uchun kuchli vositadir. Ular dasturchilarga belgilangan andazalar asosida satrlarni qidirish, tekshirish va o'zgartirish imkonini beradi. Ushbu qo'llanma JavaScript-dagi regular ifodalar, ularning sintaksisi, qo'llanilishi va ilg'or usullarini qamrab olgan to'liq ma'lumotni taqdim etadi.
Regular Ifodalar Nima?
Regular ifoda - bu qidiruv andazasini belgilaydigan belgilar ketma-ketligidir. Ushbu andazalar satrlarni moslashtirish va boshqarish uchun ishlatiladi. Regular ifodalar dasturlashda quyidagi vazifalar uchun keng qo'llaniladi:
- Ma'lumotlarni tekshirish: Foydalanuvchi kiritgan ma'lumotlarning ma'lum formatlarga (masalan, elektron pochta manzillari, telefon raqamlari) mos kelishini ta'minlash.
- Ma'lumotlarni ajratib olish: Matndan ma'lum ma'lumotlarni olish (masalan, sanalar, URL manzillar yoki narxlarni ajratib olish).
- Qidirish va almashtirish: Murakkab andazalar asosida matnni topish va almashtirish.
- Matnni qayta ishlash: Belgilangan qoidalar asosida satrlarni bo'lish, birlashtirish yoki o'zgartirish.
JavaScript-da Regular Ifodalarni Yaratish
JavaScript-da regular ifodalar ikki usulda yaratilishi mumkin:
- Regular ifoda literali yordamida: Andazani oldinga qiyshiq chiziqlar (
/) ichiga olish. RegExpkonstruktori yordamida: Andazani satr sifatida ishlatib,RegExpobyektini yaratish.
Misol:
// Regular ifoda literali yordamida
const regexLiteral = /hello/;
// RegExp konstruktori yordamida
const regexConstructor = new RegExp("hello");
Ikki usul o'rtasidagi tanlov andazaning kompilyatsiya vaqtida ma'lumligi yoki dinamik ravishda yaratilishiga bog'liq. Agar andaza oldindan ma'lum va o'zgarmas bo'lsa, literal usuldan foydalaning. Agar andazani dasturiy ravishda, ayniqsa o'zgaruvchilarni qo'shgan holda yaratish kerak bo'lsa, konstruktordan foydalaning.
Asosiy Regex Sintaksisi
Regular ifodalar moslashtiriladigan andazani ifodalovchi belgilardan iborat. Quyida ba'zi asosiy regex komponentlari keltirilgan:
- Literal belgilar: Belgilarning o'ziga mos keladi (masalan,
/a/'a' belgisiga mos keladi). - Metabelgilar: Maxsus ma'noga ega (masalan,
.,^,$,*,+,?,[],{},(),\,|). - Belgilar sinflari: Belgilar to'plamini ifodalaydi (masalan,
[abc]'a', 'b' yoki 'c' ga mos keladi). - Kvantifikatorlar: Belgi yoki guruh necha marta takrorlanishi kerakligini belgilaydi (masalan,
*,+,?,{n},{n,},{n,m}). - Langarlar (Anchors): Satrdagi pozitsiyalarga mos keladi (masalan,
^boshlanishiga,$oxiriga mos keladi).
Keng tarqalgan Metabelgilar:
.(nuqta): Yangi qator belgisidan tashqari har qanday bitta belgiga mos keladi.^(karet): Satrning boshlanishiga mos keladi.$(dollar): Satrning oxiriga mos keladi.*(yulduzcha): Oldingi belgi yoki guruhning nol yoki undan ko'p marta takrorlanishiga mos keladi.+(plyus): Oldingi belgi yoki guruhning bir yoki undan ko'p marta takrorlanishiga mos keladi.?(so'roq belgisi): Oldingi belgi yoki guruhning nol yoki bir marta takrorlanishiga mos keladi. Ixtiyoriy belgilar uchun ishlatiladi.[](kvadrat qavslar): Belgilar sinfini belgilaydi, qavs ichidagi har qanday bitta belgiga mos keladi.{}(jingalak qavslar): Mos keladigan takrorlanishlar sonini belgilaydi.{n}aynan n marta,{n,}n yoki undan ko'p marta,{n,m}n va m marta oralig'ida mos keladi.()(oddiy qavslar): Belglarni bir guruhga birlashtiradi va mos kelgan qismsatrni qamrab oladi.\(teskari slesh): Metabelgilarni ekranlashtiradi, bu ularni oddiy belgi sifatida moslashtirish imkonini beradi.|(vertikal chiziq): "yoki" operatori sifatida ishlaydi, o'zidan oldingi yoki keyingi ifodaga mos keladi.
Belgilar sinflari:
[abc]: a, b yoki c belgilaridan biriga mos keladi.[^abc]: a, b yoki c bo'lmagan har qanday belgiga mos keladi.[a-z]: a dan z gacha bo'lgan har qanday kichik harfga mos keladi.[A-Z]: A dan Z gacha bo'lgan har qanday katta harfga mos keladi.[0-9]: 0 dan 9 gacha bo'lgan har qanday raqamga mos keladi.[a-zA-Z0-9]: Har qanday harf-raqamli belgiga mos keladi.\d: Har qanday raqamga mos keladi ([0-9]ga teng).\D: Har qanday raqam bo'lmagan belgiga mos keladi ([^0-9]ga teng).\w: Har qanday so'z belgisiga mos keladi (harf-raqamli belgilar va pastki chiziq;[a-zA-Z0-9_]ga teng).\W: Har qanday so'z bo'lmagan belgiga mos keladi ([^a-zA-Z0-9_]ga teng).\s: Har qanday bo'shliq belgisiga mos keladi (bo'shliq, tabulyatsiya, yangi qator va h.k.).\S: Har qanday bo'shliq bo'lmagan belgiga mos keladi.
Kvantifikatorlar:
*: Oldingi elementga nol yoki undan ko'p marta mos keladi. Masalan,a*"", "a", "aa", "aaa" va hokazolarga mos keladi.+: Oldingi elementga bir yoki undan ko'p marta mos keladi. Masalan,a+"a", "aa", "aaa" ga mos keladi, lekin "" ga mos kelmaydi.?: Oldingi elementga nol yoki bir marta mos keladi. Masalan,a?"" yoki "a" ga mos keladi.{n}: Oldingi elementga aynan *n* marta mos keladi. Masalan,a{3}"aaa" ga mos keladi.{n,}: Oldingi elementga *n* yoki undan ko'p marta mos keladi. Masalan,a{2,}"aa", "aaa", "aaaa" va hokazolarga mos keladi.{n,m}: Oldingi elementga *n* va *m* marta (shu jumladan) oralig'ida mos keladi. Masalan,a{2,4}"aa", "aaa" yoki "aaaa" ga mos keladi.
Langarlar (Anchors):
^: Satrning boshlanishiga mos keladi. Masalan,^Hello"Hello" bilan *boshlanadigan* satrlarga mos keladi.$: Satrning oxiriga mos keladi. Masalan,World$"World" bilan *tugaydigan* satrlarga mos keladi.\b: So'z chegarasiga mos keladi. Bu so'z belgisi (\w) va so'z bo'lmagan belgi (\W) yoki satrning boshi yoki oxiri o'rtasidagi pozitsiya. Masalan,\bword\bbutun "word" so'ziga mos keladi.
Bayroqlar (Flags):
Regex bayroqlari regular ifodalarning ishlash tarzini o'zgartiradi. Ular regex literalining oxiriga qo'shiladi yoki RegExp konstruktoriga ikkinchi argument sifatida uzatiladi.
g(global): Andazaning barcha mosliklarini topadi, faqat birinchisini emas.i(ignore case): Katta-kichik harflarni e'tiborga olmagan holda moslashtirishni amalga oshiradi.m(multiline): Ko'p qatorli rejimni yoqadi, bunda^va$har bir qatorning (\nbilan ajratilgan) boshi va oxiriga mos keladi.s(dotAll): Nuqta (.) belgisiga yangi qator belgilariga ham mos kelishiga ruxsat beradi.u(unicode): To'liq Unicode qo'llab-quvvatlashini yoqadi.y(sticky): Faqat regexninglastIndexxususiyati ko'rsatgan indeksdan boshlab moslashtiradi.
JavaScript Regex Metodlari
JavaScript regular ifodalar bilan ishlash uchun bir nechta metodlarni taqdim etadi:
test(): Satrning andazaga mos kelishini tekshiradi.trueyokifalseqaytaradi.exec(): Satrda moslikni qidirishni amalga oshiradi. Mos kelgan matn va qamrab olingan guruhlarni o'z ichiga olgan massivni yoki moslik topilmasanullqaytaradi.match(): Satrni regular ifodaga moslashtirish natijalarini o'z ichiga olgan massivni qaytaradi.gbayrog'i bilan va usiz turlicha ishlaydi.search(): Satrda moslikni tekshiradi. Birinchi moslikning indeksini yoki moslik topilmasa -1 qaytaradi.replace(): Andazaning takrorlanishlarini almashtiruvchi satr yoki almashtiruvchi satrni qaytaradigan funksiya bilan almashtiradi.split(): Satrni regular ifoda asosida qismsatrlarga bo'lib, massiv hosil qiladi.
Regex Metodlaridan foydalanishga misollar:
// test()
const regex = /hello/;
const str = "hello world";
console.log(regex.test(str)); // Natija: true
// exec()
const regex2 = /hello (\w+)/;
const str2 = "hello world";
const result = regex2.exec(str2);
console.log(result); // Natija: ["hello world", "world", index: 0, input: "hello world", groups: undefined]
// match() 'g' bayrog'i bilan
const regex3 = /\d+/g; // Global ravishda bir yoki undan ko'p raqamni topadi
const str3 = "There are 123 apples and 456 oranges.";
const matches = str3.match(regex3);
console.log(matches); // Natija: ["123", "456"]
// match() 'g' bayrog'isiz
const regex4 = /\d+/;
const str4 = "There are 123 apples and 456 oranges.";
const match = str4.match(regex4);
console.log(match); // Natija: ["123", index: 11, input: "There are 123 apples and 456 oranges.", groups: undefined]
// search()
const regex5 = /world/;
const str5 = "hello world";
console.log(str5.search(regex5)); // Natija: 6
// replace()
const regex6 = /world/;
const str6 = "hello world";
const newStr = str6.replace(regex6, "JavaScript");
console.log(newStr); // Natija: hello JavaScript
// replace() funksiya bilan
const regex7 = /(\d+)-(\d+)-(\d+)/;
const str7 = "Today's date is 2023-10-27";
const newStr2 = str7.replace(regex7, (match, year, month, day) => {
return `${day}/${month}/${year}`;
});
console.log(newStr2); // Natija: Today's date is 27/10/2023
// split()
const regex8 = /, /;
const str8 = "apple, banana, cherry";
const arr = str8.split(regex8);
console.log(arr); // Natija: ["apple", "banana", "cherry"]
Regexning Ilg'or Usullari
Qamrab oluvchi guruhlar:
Qavslar () regular ifodalarda qamrab oluvchi guruhlarni yaratish uchun ishlatiladi. Qamrab olingan guruhlar mos kelgan matnning ma'lum qismlarini ajratib olish imkonini beradi. exec() va match() metodlari birinchi elementi to'liq moslik bo'lgan va keyingi elementlari qamrab olingan guruhlar bo'lgan massivni qaytaradi.
const regex = /(\d{4})-(\d{2})-(\d{2})/;
const dateString = "2023-10-27";
const match = regex.exec(dateString);
console.log(match[0]); // Natija: 2023-10-27 (To'liq moslik)
console.log(match[1]); // Natija: 2023 (Birinchi qamrab olingan guruh - yil)
console.log(match[2]); // Natija: 10 (Ikkinchi qamrab olingan guruh - oy)
console.log(match[3]); // Natija: 27 (Uchinchi qamrab olingan guruh - kun)
Nomlangan qamrab oluvchi guruhlar:
ES2018 da nomlangan qamrab oluvchi guruhlar joriy etildi, ular (? sintaksisi yordamida qamrab oluvchi guruhlarga nom berish imkonini beradi. Bu kodni o'qilishi oson va qo'llab-quvvatlanishi qulay qiladi.
const regex = /(?\d{4})-(?\d{2})-(?\d{2})/;
const dateString = "2023-10-27";
const match = regex.exec(dateString);
console.log(match.groups.year); // Natija: 2023
console.log(match.groups.month); // Natija: 10
console.log(match.groups.day); // Natija: 27
Qamrab olinmaydigan guruhlar:
Agar siz regexning qismlarini qamrab olmasdan guruhlash zarurati bo'lsa (masalan, guruhga kvantifikator qo'llash uchun), siz (?:...) sintaksisi bilan qamrab olinmaydigan guruhdan foydalanishingiz mumkin. Bu qamrab olingan guruhlar uchun ortiqcha xotira ajratilishining oldini oladi.
const regex = /(?:https?:\/\/)?([\w\.]+)/; // URL ga mos keladi, lekin faqat domen nomini qamrab oladi
const url = "https://www.example.com/path";
const match = regex.exec(url);
console.log(match[1]); // Natija: www.example.com
Atrofga qarash (Lookarounds):
Lookarounds - bu nol kenglikdagi tasdiqlashlar bo'lib, ular satrdagi pozitsiyani undan oldin keluvchi (lookbehind) yoki keyin keluvchi (lookahead) andazaga qarab moslashtiradi, lekin lookaround andazasining o'zini moslikka kiritmaydi.
- Ijobiy oldinga qarash:
(?=...)Lookahead ichidagi andaza joriy pozitsiyadan *keyin* kelsa, mos keladi. - Salbiy oldinga qarash:
(?!...)Lookahead ichidagi andaza joriy pozitsiyadan *keyin* kelmasa, mos keladi. - Ijobiy orqaga qarash:
(?<=...)Lookbehind ichidagi andaza joriy pozitsiyadan *oldin* kelsa, mos keladi. - Salbiy orqaga qarash:
(? Lookbehind ichidagi andaza joriy pozitsiyadan *oldin* kelmasa, mos keladi.
Misol:
// Ijobiy oldinga qarash: Faqat USD dan keyin kelgan narxni olish
const regex = /\d+(?= USD)/;
const text = "The price is 100 USD";
const match = text.match(regex);
console.log(match); // Natija: ["100"]
// Salbiy oldinga qarash: Faqat raqamdan keyin kelmagan so'zni olish
const regex2 = /\b\w+\b(?! \d)/;
const text2 = "apple 123 banana orange 456";
const matches = text2.match(regex2);
console.log(matches); // Natija: null, chunki match() 'g' bayrog'isiz faqat birinchi moslikni qaytaradi, bu esa bizga kerak emas.
// tuzatish uchun:
const regex3 = /\b\w+\b(?! \d)/g;
const text3 = "apple 123 banana orange 456";
const matches3 = text3.match(regex3);
console.log(matches3); // Natija: [ 'banana' ]
// Ijobiy orqaga qarash: Faqat $ dan oldin kelgan qiymatni olish
const regex4 = /(?<=\$)\d+/;
const text4 = "The price is $200";
const match4 = text4.match(regex4);
console.log(match4); // Natija: ["200"]
// Salbiy orqaga qarash: Faqat 'not' so'zidan oldin kelmagan so'zni olish
const regex5 = /(?
Orqaga havolalar (Backreferences):
Orqaga havolalar bir xil regular ifoda ichida avval qamrab olingan guruhlarga murojaat qilish imkonini beradi. Ular \1, \2 va hokazo sintaksisidan foydalanadi, bu yerda raqam qamrab olingan guruh raqamiga mos keladi.
const regex = /([a-z]+) \1/;
const text = "hello hello world";
const match = regex.exec(text);
console.log(match); // Natija: ["hello hello", "hello", index: 0, input: "hello hello world", groups: undefined]
Regular Ifodalarning Amaliy Qo'llanmalari
Elektron Pochta Manzillarini Tekshirish:
Regular ifodalarning keng tarqalgan qo'llanilishidan biri bu elektron pochta manzillarini tekshirishdir. Mukammal elektron pochta tekshirish regexi juda murakkab bo'lsa-da, quyida soddalashtirilgan misol keltirilgan:
const emailRegex = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/;
console.log(emailRegex.test("test@example.com")); // Natija: true
console.log(emailRegex.test("invalid-email")); // Natija: false
console.log(emailRegex.test("test@sub.example.co.uk")); // Natija: true
Matndan URL manzillarini ajratib olish:
Siz matn blokidan URL manzillarini ajratib olish uchun regular ifodalardan foydalanishingiz mumkin:
const urlRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g;
const text = "Visit our website at https://www.example.com or check out http://blog.example.org.";
const urls = text.match(urlRegex);
console.log(urls); // Natija: ["https://www.example.com", "http://blog.example.org"]
CSV Ma'lumotlarini Tahlil qilish:
Regular ifodalar CSV (Vergul bilan ajratilgan qiymatlar) ma'lumotlarini tahlil qilish uchun ishlatilishi mumkin. Quyida qo'shtirnoq ichidagi maydonlarni hisobga olgan holda CSV satrini qiymatlar massiviga bo'lish misoli keltirilgan:
const csvString = 'John,Doe,"123, Main St",New York';
const csvRegex = /(?:"([^"]*(?:""[^"]*)*)")|([^,]+)/g; //Tuzatilgan CSV regex
let values = [];
let match;
while (match = csvRegex.exec(csvString)) {
values.push(match[1] ? match[1].replace(/""/g, '"') : match[2]);
}
console.log(values); // Natija: ["John", "Doe", "123, Main St", "New York"]
Xalqaro Telefon Raqamlarini Tekshirish
Xalqaro telefon raqamlarini tekshirish turli formatlar va uzunliklar tufayli murakkabdir. Ishonchli yechim ko'pincha kutubxonadan foydalanishni talab qiladi, ammo soddalashtirilgan regex asosiy tekshiruvni ta'minlashi mumkin:
const phoneRegex = /^\+(?:[0-9] ?){6,14}[0-9]$/;
console.log(phoneRegex.test("+1 555 123 4567")); // Natija: true (AQSh misoli)
console.log(phoneRegex.test("+44 20 7946 0500")); // Natija: true (Buyuk Britaniya misoli)
console.log(phoneRegex.test("+81 3 3224 5000")); // Natija: true (Yaponiya misoli)
console.log(phoneRegex.test("123-456-7890")); // Natija: false
Parol Murakkabligini Tekshirish
Regular ifodalar parol murakkabligi siyosatlarini amalga oshirish uchun foydalidir. Quyidagi misol minimal uzunlik, katta harf, kichik harf va raqam mavjudligini tekshiradi.
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/;
console.log(passwordRegex.test("P@ssword123")); // Natija: true
console.log(passwordRegex.test("password")); // Natija: false (katta harf yoki raqam yo'q)
console.log(passwordRegex.test("Password")); // Natija: false (raqam yo'q)
console.log(passwordRegex.test("Pass123")); // Natija: false (kichik harf yo'q)
console.log(passwordRegex.test("P@ss1")); // Natija: false (8 ta belgidan kam)
Regexni Optimallashtirish Usullari
Regular ifodalar, ayniqsa murakkab andazalar yoki katta hajmdagi ma'lumotlar uchun hisoblash jihatdan qimmat bo'lishi mumkin. Quyida regex ishlash samaradorligini optimallashtirish uchun ba'zi usullar keltirilgan:
- Aniq bo'ling: Keragidan ortiq narsaga mos kelishi mumkin bo'lgan juda umumiy andazalardan foydalanishdan saqlaning.
- Langarlardan foydalaning: Iloji boricha regexni satrning boshi yoki oxiriga (
^,$) bog'lang. - Orqaga qaytishdan (Backtracking) saqlaning: Tegishli holatlarda egalik kvantifikatorlaridan (masalan,
+o'rniga++) yoki atomik guruhlardan ((?>...)) foydalanib, orqaga qaytishni minimallashtiring. - Bir marta kompilyatsiya qiling: Agar siz bir xil regexdan bir necha marta foydalansangiz, uni bir marta kompilyatsiya qiling va
RegExpobyektini qayta ishlating. - Belgilar sinflaridan oqilona foydalaning: Belgilar sinflari (
[]) odatda alternativalardan (|) tezroq ishlaydi. - Sodda tuting: Tushunish va qo'llab-quvvatlash qiyin bo'lgan o'ta murakkab regexlardan saqlaning. Ba'zan murakkab vazifani bir nechta soddaroq regexlarga bo'lish yoki boshqa satrlarni boshqarish usullaridan foydalanish samaraliroq bo'lishi mumkin.
Keng Tarqalgan Regex Xatolari
- Metabelgilarni ekranlashtirishni unutish:
.,*,+,?,$,^,(,),[,],{,},|va\kabi maxsus belgilarni oddiy belgi sifatida moslashtirishni istaganda ularni ekranlashtirmaslik. .(nuqta) ni haddan tashqari ko'p ishlatish: Nuqta har qanday belgiga mos keladi (ba'zi rejimlarda yangi qatordan tashqari), bu ehtiyotkorlik bilan ishlatilmasa, kutilmagan mosliklarga olib kelishi mumkin. Iloji boricha belgilar sinflari yoki boshqa cheklovchi andazalardan foydalanib, aniqroq bo'ling.- Ochko'zlik (Greediness): Odatiy bo'lib,
*va+kabi kvantifikatorlar ochko'zdir va imkon qadar ko'proq mos kelishga harakat qiladi. Eng qisqa mos keladigan satrni topish kerak bo'lganda dangasa kvantifikatorlardan (*?,+?) foydalaning. - Langarlarni noto'g'ri ishlatish:
^(satr/qator boshi) va$(satr/qator oxiri) ning ishlashini noto'g'ri tushunish noto'g'ri moslashuvlarga olib kelishi mumkin. Ko'p qatorli satrlar bilan ishlayotganda va^va$har bir qatorning boshi va oxiriga mos kelishini xohlasangiz,m(multiline) bayrog'idan foydalanishni unutmang. - Chekka holatlarni hisobga olmaslik: Barcha mumkin bo'lgan kiritish stsenariylari va chekka holatlarni hisobga olmaslik xatoliklarga olib kelishi mumkin. Regexlaringizni turli xil kiritishlar, jumladan, bo'sh satrlar, noto'g'ri belgilar va chegara shartlari bilan sinchkovlik bilan tekshiring.
- Ishlash samaradorligi muammolari: O'ta murakkab va samarasiz regexlarni yaratish, ayniqsa katta hajmdagi ma'lumotlar bilan ishlashda, ishlash samaradorligi muammolarini keltirib chiqarishi mumkin. Aniqroq andazalardan foydalanib, keraksiz orqaga qaytishdan saqlanib va qayta-qayta ishlatiladigan regexlarni kompilyatsiya qilib, regexlaringizni optimallashtiring.
- Belgilar kodirovkasini e'tiborsiz qoldirish: Belgilar kodirovkalarini (ayniqsa Unicode) to'g'ri ishlatmaslik kutilmagan natijalarga olib kelishi mumkin. Unicode belgilari bilan ishlaganda to'g'ri moslashuvni ta'minlash uchun
ubayrog'idan foydalaning.
Xulosa
Regular ifodalar JavaScript-da andazalarni moslashtirish va matnni boshqarish uchun qimmatli vositadir. Regex sintaksisi va usullarini o'zlashtirish ma'lumotlarni tekshirishdan tortib murakkab matnni qayta ishlashgacha bo'lgan keng ko'lamli muammolarni samarali hal qilish imkonini beradi. Ushbu qo'llanmada muhokama qilingan tushunchalarni tushunib, real dunyo misollari bilan mashq qilib, siz regular ifodalardan foydalanishda mahoratli bo'lib, JavaScript dasturlash ko'nikmalaringizni oshirishingiz mumkin.
Unutmangki, regular ifodalar murakkab bo'lishi mumkin va ularni regex101.com yoki regexr.com kabi onlayn regex sinovchilar yordamida sinchkovlik bilan tekshirish ko'pincha foydalidir. Bu sizga mosliklarni vizual ko'rish va har qanday muammolarni samarali tuzatish imkonini beradi. Dasturlashda omad!